package fr.rinie.android_first_step;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * All copyright reserved.
 * User: romain
 * Date: 11/20/13
 * Time: 10:12 PM
 * Please contact romain.rinie@xcom.de before any modification/distribution.
 */
public class FishDB {
    private static final int VERSION_BDD = 1;
    private static final String DB_NAME = "FullDB.db";
    private static final String DB_PATH = "/data/data/fr.rinie.android_first_step/databases/";

    private static final String FISH_TABLE = "fish_table";
    private static final String COL_ID = "ID";
    private static final int NUM_COL_ID = 0;
    private static final String COL_SC_NAME = "scientificName";
    private static final int NUM_SC_NAME = 1;
    private static final String COL_NAME = "commonName";
    private static final int NUM_NAME = 2;
    private static final String COL_DESCRIPTOR = "describer";
    private static final int NUM_DESCRIPTOR = 3;
    private static final String COL_FAMILLY = "Famille";
    private static final int NUM_FAMILLY = 4;
    private static final String COL_TEMP_MIN = "TempMin";
    private static final int NUM_TEMP_MIN = 5;
    private static final String COL_TEMP_MAX = "TempMax";
    private static final int NUM_TEMP_MAX = 6;
    private static final String COL_TEMP_REPRO = "TempRepro";
    private static final int NUM_TEMP_REPRO = 7;
    private static final String COL_PH_MIN = "PHMin";
    private static final int NUM_PH_MIN = 8;
    private static final String COL_PH_MAX = "PHMax";
    private static final int NUM_PH_MAX = 9;
    private static final String COL_PH_REPRO = "PHRepro";
    private static final int NUM_PH_REPRO = 10;
    private static final String COL_GH_MIN = "GHMin";
    private static final int NUM_GH_MIN = 11;
    private static final String COL_GH_MAX = "GHMax";
    private static final int NUM_GH_MAX = 12;
    private static final String COL_GH_REPRO = "GHRepro";
    private static final int NUM_GH_REPRO = 13;
    private static final String COL_SIZE_MALE = "TailleMale";
    private static final int NUM_SIZE_MALE = 14;
    private static final String COL_SIZE_FEMALE = "TailleFemale";
    private static final int NUM_SIZE_FEMALE = 15;
    private static final String COL_LIFE_EXPECTANCY = "EsperanceVie";
    private static final int NUM_LIFE_EXPECTANCY = 16;
    private static final String COL_LIFE_ZONE = "ZoneDeVie";
    private static final int NUM_LIFE_ZONE = 17;
    private static final String COL_ORIGINE = "Origine";
    private static final int NUM_ORIGINE = 18;
    private static final String COL_DESCRIPTION = "Description";
    private static final int NUM_DESCRIPTION = 19;
    private static final String COL_DISMORPHISME = "Dimorphisme";
    private static final int NUM_DISMORPHISME = 20;
    private static final String COL_BEHAVIOUR = "Comportement";
    private static final int NUM_BEHAVIOUR = 21;
    private static final String COL_REPRODUCTION = "Reproduction";
    private static final int NUM_REPRODUCTION = 22;

    private SQLiteDatabase bdd;
    private final MySQLiteDataBase mySQLiteDataBase;
    private final Context myContext;

    public FishDB(Context context) {
        mySQLiteDataBase = new MySQLiteDataBase(context, DB_NAME, null, VERSION_BDD);
        myContext = context;
    }

    public void open(){
        String myPath = DB_PATH + DB_NAME;
        bdd = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    }

    public void close(){
        bdd.close();
    }

    public FishContainer.Fish getFishByScientifiqueName(String scientifiqueName) {
        Cursor c = bdd.query(FISH_TABLE, new String[] {COL_ID, COL_SC_NAME, COL_NAME, COL_DESCRIPTOR, COL_FAMILLY, COL_TEMP_MIN, COL_TEMP_MAX, COL_TEMP_REPRO, COL_PH_MIN,COL_PH_MAX, COL_PH_REPRO, COL_GH_MIN, COL_GH_MAX, COL_GH_REPRO, COL_SIZE_MALE, COL_SIZE_FEMALE,COL_LIFE_EXPECTANCY, COL_LIFE_ZONE, COL_ORIGINE, COL_DESCRIPTION, COL_DISMORPHISME, COL_BEHAVIOUR, COL_REPRODUCTION}, COL_SC_NAME + " LIKE \"%" + scientifiqueName + "%\"", null, null, null, null);
        return cursorToFish(c);
    }
    public List<FishContainer.Fish> getAllFish() {
        List<FishContainer.Fish> fishList = new ArrayList<>();
        String selectQuery = "SELECT  * FROM " + FISH_TABLE;
        Cursor cursor = bdd.rawQuery(selectQuery, null);
        if (cursor.moveToFirst()) {
            do {
                fishList.add(getFishFromCursorCurrentPos(cursor));
            } while (cursor.moveToNext());
        }
        return fishList;
    }

    private FishContainer.Fish cursorToFish(Cursor c){
        if (c.getCount() == 0) {
            return null;
        }
        c.moveToFirst();
        FishContainer.Fish fish = getFishFromCursorCurrentPos(c);
        c.close();
        return fish;
    }

    private FishContainer.Fish getFishFromCursorCurrentPos(Cursor c) {
        FishContainer.Fish fish = new FishContainer.Fish();
        fish.scientificName = c.getString(NUM_SC_NAME);
        fish.commonName =  new ObjectSerializer().deserialyze(c.getString(NUM_NAME));
        fish.describer = c.getString(NUM_DESCRIPTOR);
        fish.family = c.getString(NUM_FAMILLY);
        FishContainer.Fish.Temperature temperature = new FishContainer.Fish.Temperature();
        temperature.tempMax = new BigDecimal(c.getString(NUM_TEMP_MAX));
        temperature.tempRepro = new BigDecimal(c.getString(NUM_TEMP_REPRO));
        temperature.tempMin = new BigDecimal(c.getString(NUM_TEMP_MIN));
        fish.temperature = temperature;
        FishContainer.Fish.Acidity acidity = new FishContainer.Fish.Acidity();
        acidity.phRepro = new BigDecimal(c.getString(NUM_PH_REPRO));
        acidity.phMax = new BigDecimal(c.getString(NUM_PH_MAX));
        acidity.phMin = new BigDecimal(c.getString(NUM_PH_MIN));
        fish.acidity = acidity;
        FishContainer.Fish.Hardness hardness = new FishContainer.Fish.Hardness();
        hardness.ghRepro = new BigDecimal(c.getString(NUM_GH_REPRO));
        hardness.ghMax = new BigDecimal(c.getString(NUM_GH_MAX));
        hardness.ghMin = new BigDecimal(c.getString(NUM_GH_MIN));
        fish.hardness = hardness;
        FishContainer.Fish.Size size = new FishContainer.Fish.Size();
        size.malSize = new BigDecimal(c.getString(NUM_SIZE_MALE));
        size.femaleSize = new BigDecimal(c.getString(NUM_SIZE_FEMALE));
        fish.size = size;
        fish.lifeExpectancy = c.getString(NUM_LIFE_EXPECTANCY);
        fish.lifeZone = c.getString(NUM_LIFE_ZONE);
        fish.origin = c.getString(NUM_ORIGINE);
        fish.description = c.getString(NUM_DESCRIPTION);
        fish.dimorphism = c.getString(NUM_DISMORPHISME);
        fish.behaviour = c.getString(NUM_BEHAVIOUR);
        fish.reproduction = c.getString(NUM_REPRODUCTION);
        return fish;
    }

    /**New method created to preload DataBase**/
    public void createDataBase() throws IOException {
        boolean dbExist = checkDataBase();
        if(dbExist){
            //do nothing - database already exist
        }else{
            //By calling this method and empty database will be created into the default system path
            //of your application so we are gonna be able to overwrite that database with our database.
            mySQLiteDataBase.getReadableDatabase();
            try {
                copyDataBase();

            } catch (IOException e) {

                throw new Error("Error copying database");
            }
        }
    }
    /**
     * Check if the database already exist to avoid re-copying the file each time you open the application.
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase(){

        SQLiteDatabase checkDB = null;

        try{
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
        }catch(SQLiteException e){
            //database does't exist yet.
        }
        if(checkDB != null){
            checkDB.close();
        }
        return checkDB != null;
    }
    /**
     * Copies your database from your local assets-folder to the just created empty database in the
     * system folder, from where it can be accessed and handled.
     * This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException{

        //Open your local db as the input stream
        InputStream myInput = myContext.getAssets().open(DB_NAME);

        // Path to the just created empty db
        String outFileName = DB_PATH + DB_NAME;

        //Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        //transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
        }

        //Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

}
